// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

#region

using System.Security.Cryptography;

#endregion

namespace Neto.Helpers;

/// <summary>
///     使用Random类生成伪随机数
/// </summary>
public static class RandomHelper
{
    // 使用静态RandomNumberGenerator实例以提高效率
    private static readonly RandomNumberGenerator Rng = RandomNumberGenerator.Create();

    #region 生成随机字节

    /// <summary>
    ///     生成指定数量的随机字节
    /// </summary>
    /// <param name="count">要生成的字节数量</param>
    /// <returns>包含随机字节的数组</returns>
    public static byte[] GetBytes(int count)
    {
        // 创建一个字节数组来存储随机字节
        var bytes = new byte[count];
        // 使用Rng填充字节数组
        Rng.GetBytes(bytes);
        return bytes;
    }

    #endregion 生成随机字节

    #region 生成指定范围的随机整数

    /// <summary>
    ///     生成一个指定范围的随机整数，该随机数范围包括最小值，但不包括最大值
    /// </summary>
    /// <param name="min">最小值</param>
    /// <param name="max">最大值</param>
    /// <returns>生成的随机整数</returns>
    public static int GetInt(int min, int max)
    {
        // 生成一个32位的随机整数
        var bytes = new byte[sizeof(int)];
        Rng.GetBytes(bytes);

        // 将字节转换为整数，取绝对值以确保正数
        unchecked
        {
            var value = BitConverter.ToInt32(bytes, 0);
            // 使用取模运算生成指定范围的随机整数
            return Math.Abs(value % (max - min + 1)) + min;
        }
    }

    #endregion 生成指定范围的随机整数

    #region 生成0.0到1.0的随机小数

    /// <summary>
    ///     生成一个0.0到1.0的随机小数
    /// </summary>
    /// <returns>生成的随机小数</returns>
    public static double GetDouble()
    {
        // 生成一个双精度浮点数的字节表示
        var bytes = new byte[sizeof(double)];
        Rng.GetBytes(bytes);
        // 将字节转换为双精度浮点数
        return BitConverter.ToDouble(bytes, 0);
    }

    #endregion 生成0.0到1.0的随机小数

    #region 生成随机字符串

    /// <summary>
    ///     从字符串里随机得到，规定个数的字符串.
    /// </summary>
    /// <param name="length">生成的字符串长度</param>
    /// <param name="randType">随机类型（数字，字母，数字+字母）</param>
    /// <param name="chars">随机用的字符</param>
    /// <returns>生成的随机字符串</returns>
    public static string GetString(int length, RandType randType = RandType.Normarl, string chars = "")
    {
        if (length <= 0) return string.Empty; // 处理边界条件

        // 定义所有可能的字符
        var allChar = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        if (!string.IsNullOrWhiteSpace(chars))
            allChar = chars;
        else
            allChar = randType switch
            {
                RandType.NumAndStr => "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
                RandType.Num => "0123456789",
                RandType.Str => "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
                _ => allChar
            };

        var randomCode = "";
        // 用于生成随机整数的临时字节数组
        var randomBytes = new byte[sizeof(int)];

        // 使用新的RandomNumberGenerator实例以避免在循环中影响其他方法的随机性
        using var rng = RandomNumberGenerator.Create();
        for (var i = 0; i < length; i++)
        {
            rng.GetBytes(randomBytes);
            // 将字节转换为整数，然后取模得到字符索引
            var index = Math.Abs(BitConverter.ToInt32(randomBytes, 0)) % allChar.Length;
            //如果得到的索引小于0，则将其设置为0
            if (index < 0)
                index = 0;
            // 如果得到的索引大于等于字符数组的长度，则将其设置为最后一个索引
            else if (index >= allChar.Length) index = allChar.Length - 1;

            // 添加字符到随机字符串
            randomCode += allChar[index];
        }

        return randomCode;
    }

    #endregion 生成随机字符串
}

/// <summary>
///     随机类型
/// </summary>
public enum RandType
{
    Normarl,

    /// <summary>
    ///     数字
    /// </summary>
    Num,

    /// <summary>
    ///     字母
    /// </summary>
    Str,

    /// <summary>
    ///     数字+字母
    /// </summary>
    NumAndStr
}